//#if SILVERLIGHT

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using AbstraX.Contracts;
#if SILVERLIGHT
using AbstraX.ClientInterfaces;
#else
using AbstraX.ServerInterfaces;
#endif
using AbstraX;
using System.Reflection;
using System.ServiceModel.DomainServices.Client;
using System.Net;
using System.Windows;
using System.Diagnostics;
using AbstraX.BuildWizard;
using Microsoft.Practices.Unity;
using BuildInvokeOperation = AbstraX.Contracts.BuildInvokeOperation;
using UIObjects;
using System.IO;

namespace AbstraX.Services
{
    public class ProviderClientService : IProviderClientService
    {
        private IWizardContainer wizardContainer;
        private ILog log;

        private class UIParms
        {
            public string Parms;
            public string URL;
        }

        public ILog Log
        {
            get
            {
                return log;
            }
        }

        public ProviderClientService(ILog log)
        {
            this.log = log;

            ProviderClientManager.OnGeneralMessage += new OnGeneralMessageHandler(OnGeneralMessage);
            ProviderClientManager.OnPercentComplete += new OnPercentCompleteHandler(OnPercentComplete);
            ProviderClientManager.OnShowUI += new OnShowUIHandler(OnShowUI);
            ProviderClientManager.OnGeneralError += new OnGeneralErrorHandler(OnGeneralError);
            ProviderClientManager.OnFatalError += new OnFatalErrorHandler(OnFatalError);
        }

        private void OnGeneralError(RemotableException exception)
        {
            ProviderClientManager.SetStatus(exception.Message);
        }

        private void OnFatalError(RemotableException exception)
        {
            ProviderClientManager.SetStatus(exception.Message);
        }

        private void OnBuildComplete()
        {
            ProviderClientManager.SetStatus("BuildComplete");
        }

        private void OnShowUI(string uiComponentURL, string parms)
        {
            var client = new WebClient();
            var uiParms = new UIParms
            {
                URL = uiComponentURL,
                Parms = parms
            };

            ProviderClientManager.SetStatus("Loading " + uiComponentURL);

            client.OpenReadCompleted += new OpenReadCompletedEventHandler(OnAssemblyOpened);
            client.OpenReadAsync(new Uri(uiComponentURL, UriKind.Relative), uiParms);
        }

        private void OnAssemblyOpened(object sender, OpenReadCompletedEventArgs e)
        {
            var assemblyPart = new AssemblyPart();
            var assembly = assemblyPart.Load(e.Result);
            var frameFound = false;
            var parms = (UIParms)e.UserState;

            foreach (Type type in assembly.GetTypes())
            {
                var interfaces = type.GetInterfaces().AsQueryable().Cast<Type>();

                if (interfaces.Any(t => t.Name == "IWizardFrame"))
                {
                    var frameObject = Activator.CreateInstance(type);
                    var wizardFrame = (IWizardFrame)frameObject;

                    wizardFrame.Parms = parms.Parms;
                    wizardFrame.URL = parms.URL;
                    wizardFrame.WizardContainer = wizardContainer;

                    if (!wizardContainer.IsLoaded)
                    {
                        wizardContainer.Load(ProviderClientManager.BuildProxy);
                    }

                    wizardContainer.Add(wizardFrame);

                    frameFound = true;
                }
            }

            if (!frameFound)
            {
                Debugger.Break();
            }
        }

        private void OnGeneralMessage(string message)
        {
            ProviderClientManager.SetStatus(message);
        }

        private void OnPercentComplete(float percentComplete)
        {
            ProviderClientManager.SetStatus("Percent Complete " + percentComplete.ToString() + "%");
        }

        public IRootsCollection ProviderRoots
        {
            get
            {
                return ProviderClientManager.ProviderRoots;
            }
        }

        public ImageInvokeOperation LoadImageForUrl(string url)
        {
            // Shenkey TODO - Load images local to AbstraX.ClientInterfaces project            
            byte[] imageData;
            Stream st = Assembly.GetCallingAssembly().GetManifestResourceStream(url);
            int length = (int)st.Length;
            imageData = new byte[length];
            st.Read(imageData, 0, (int)st.Length);
            st.Close();
            var imageInvokeOperation = new ImageInvokeOperation(imageData);
            return imageInvokeOperation;

        }

        public ImageInvokeOperation LoadImageForUrl(string itemTypeName, string url)
        {
            byte[] imageData;
            var name = itemTypeName + ":" + url + ".png";

            if (ProviderClientManager.ImageInCache(name, out imageData))
            {
                var imageInvokeOperation = new ImageInvokeOperation(imageData);
                return imageInvokeOperation;
            }
            else
            {
                var imageInvokeOperation = new ImageInvokeOperation();
                var nameSpace = itemTypeName.Substring(0, itemTypeName.Remove(itemTypeName.LastIndexOf('.')).LastIndexOf('.'));
                var context = ProviderClientManager.Contexts[nameSpace];
                var methodInfo = context.GetType().GetMethods().FirstOrDefault(m => m.Name == "GetImageForUrl" && m.GetParameters().Count() == 1);
                var invokeOperation = (InvokeOperation)methodInfo.Invoke(context, new object[] { url });

                invokeOperation.Completed += (sender, e) =>
                {
                    imageData = (byte[])invokeOperation.Value;
                    imageInvokeOperation.SetCompleted(imageData);

                    ProviderClientManager.CacheImage(name, ProviderClientManager.ImageDownloadType.Folder, imageData);
                };

                return imageInvokeOperation;
            }
        }

        public ImageInvokeOperation LoadImageForFolder(string itemTypeName, string keyName)
        {
            byte[] imageData;
            var name = itemTypeName + ":" + keyName + ".png";

            if (ProviderClientManager.ImageInCache(name, out imageData))
            {
                var imageInvokeOperation = new ImageInvokeOperation(imageData);
                return imageInvokeOperation;
            }
            else
            {
                var imageInvokeOperation = new ImageInvokeOperation();
                var nameSpace = itemTypeName.Substring(0, itemTypeName.Remove(itemTypeName.LastIndexOf('.')).LastIndexOf('.'));
                var context = ProviderClientManager.Contexts[nameSpace];
                var methodInfo = context.GetType().GetMethods().FirstOrDefault(m => m.Name == "GetImageForFolder" && m.GetParameters().Count() == 1);
                var invokeOperation = (InvokeOperation)methodInfo.Invoke(context, new object[] { keyName });

                invokeOperation.Completed += (sender, e) =>
                {
                    imageData = (byte[])invokeOperation.Value;
                    imageInvokeOperation.SetCompleted(imageData);

                    ProviderClientManager.CacheImage(name, ProviderClientManager.ImageDownloadType.Folder, imageData);
                };

                return imageInvokeOperation;
            }
        }

        public ImageInvokeOperation LoadImageForItemType(string itemTypeName)
        {
            byte[] imageData;
            var name = itemTypeName + ".png";

            if (ProviderClientManager.ImageInCache(name, out imageData))
            {
                var imageInvokeOperation = new ImageInvokeOperation(imageData);
                return imageInvokeOperation;
            }
            else
            {
                var imageInvokeOperation = new ImageInvokeOperation();
                var nameSpace = itemTypeName.Substring(0, itemTypeName.Remove(itemTypeName.LastIndexOf('.')).LastIndexOf('.'));
                var context = ProviderClientManager.Contexts[nameSpace];
                var methodInfo = context.GetType().GetMethods().FirstOrDefault(m => m.Name == "GetImageForItemType" && m.GetParameters().Count() == 1);
                var invokeOperation = (InvokeOperation)methodInfo.Invoke(context, new object[] { itemTypeName.Replace(".Client.", ".") });

                invokeOperation.Completed += (sender, e) =>
                {
                    imageData = (byte[])invokeOperation.Value;
                    imageInvokeOperation.SetCompleted(imageData);

                    ProviderClientManager.CacheImage(name, ProviderClientManager.ImageDownloadType.Folder, imageData);
                };

                return imageInvokeOperation;
            }
        }

        public T GenerateItemFromID<T>(string id) where T : IBase
        {
            return default(T);
        }

        public BuildInvokeOperation Build(string id)
        {
#if SILVERLIGHT
            var invokeOperation = new BuildInvokeOperation();
            var invokeOperation2 = ProviderClientManager.BuildMiddleLayer(id);

            invokeOperation2.OnBuildCompleted += (sender2, e2) =>
            {
                ProviderClientManager.StopEvents();
                invokeOperation.SetCompleted();
            };

            invokeOperation2.ExceptionOccured += (sender2, e2) =>
            {
                invokeOperation.SetException(e2.Exception);
            };

            return invokeOperation;
#else
            return null;
#endif
        }

        public bool BuildInProgress
        {
            get
            {
                return ProviderClientManager.BuildInProgress;
            }
        }

        public IWizardContainer WizardContainer
        {
            get
            {
                return wizardContainer;
            }
            set
            {
                wizardContainer = value;
            }
        }
    }
}

//#endif